package com.xwj.shiro.realm;

import com.xwj.entity.RaRole;
import com.xwj.entity.RaRoleRoot;
import com.xwj.entity.RaRoot;
import com.xwj.entity.UserInfo;
import com.xwj.service.Impl.RaRoleRootServiceImpl;
import com.xwj.service.Impl.RaRoleServiceImpl;
import com.xwj.service.Impl.RaRootServiceImpl;
import com.xwj.service.Impl.RaUserServiceImpl;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Created by thinkjoy on 2017/7/10.
 */
public class AdminShiroRealm extends AuthorizingRealm {

    @Autowired
    @Lazy
    private RaUserServiceImpl userInfoService;
    @Autowired
    @Lazy
    private RaRootServiceImpl rootService;
    @Autowired
    @Lazy
    private RaRoleRootServiceImpl roleRootService;
    @Autowired
    @Lazy
    private RaRoleServiceImpl roleService;

    public AdminShiroRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
        super(cacheManager, matcher);
    }

    /**
     * 授权
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        List<String> permissions = new ArrayList<>();//权限集合
        List<String> roles = new ArrayList<>();//角色集合
        List rootIds = new ArrayList<>();
        String accountID = (String) principalCollection.getPrimaryPrincipal();
        UserInfo userInfo = userInfoService.findUserByAccountID(accountID, "0");
        RaRole role = roleService.findRoleById(userInfo.getRoleid());
        if (role == null && userInfo.getRoleid() == 0)
            return info;
        List<RaRoleRoot> raRoleRoots = roleRootService.findRoleRootByRoleId(userInfo.getRoleid());
        for (RaRoleRoot r : raRoleRoots) rootIds.add(r.getRootid());
        List<RaRoot> raRoots = rootService.findRootByIds(rootIds);
        for (RaRoot root : raRoots) permissions.add(root.getRoot());
        roles.add(role.getRole());
        info.addRoles(roles);
        info.addStringPermissions(permissions);
        return info;
    }

    /**
     * 认证
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String accountID = (String) authenticationToken.getPrincipal();
        DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
        DefaultSessionManager sessionManager = (DefaultSessionManager) securityManager.getSessionManager();
        Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();//获取当前已登录的用户session列表
        sessions.forEach(session -> {  //保证同一时间同一个号只能在线一次
            if (accountID.equals(String.valueOf(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY)))) //清除该用户以前登录时保存的session
                sessionManager.getSessionDAO().delete(session);
        });
        UserInfo userInfo = userInfoService.findUserByAccountID(accountID, "0");
        if (userInfo == null) return null;
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(accountID, userInfo.getPassword(),
                ByteSource.Util.bytes(userInfo.getSalt()), this.getName());
        return simpleAuthenticationInfo;
    }

    @Override
    public String getName() {
        return getClass().getName();
    }
}
